#include <vector>
#include <queue>
#include "structures.h"
#include "common.h"
#include "ruler.h"

using namespace std;

/**
 * Public constructor. Makes internal REFERENCES to all specified arguments
 */
ruler::ruler(const game_settings& _settings, const game_field& _field):
	settings(_settings), field(_field)
{
}

/**
 * Returns a two-dimensional vector D through the fourth argument. D[i][j]
 * contains the distance from cell (from_x; from_y) to cell (i; j). If
 * D[i][j] = -1, then cell (i; j) is unreachable in max_distance steps.
 * D[from_x][from_y] is always set to 0.
 */
void ruler::measure_distances(int from_x, int from_y, int max_distance, vector<vector<int>>& distances)
{
	queue<point> q;
	point p(from_x, from_y);
	
	distances.resize(2 * settings.field_radius + 1);
	for (int i = 0; i < 2 * settings.field_radius + 1; i++)
	{
		distances[i].resize(2 * settings.field_radius + 1);
		for (int j = 0; j < 2 * settings.field_radius + 1; j++)
		{
			distances[i][j] = -1;
		}
	}

	distances[p.x][p.y] = 0;

	//
	// TODO: Clean up BFS from duplicate condition checks
	//

	q.push(p);
	while(!q.empty())
	{
		p = q.front();
		q.pop();

		// Ignore cells, which were already analyzed (ex
		/*
		if(distances[p.x][p.y] != -1 && (p.x != from_x || p.y != from_y))
		{
			continue;
		}
		*/

		// Mark all cells farther than specified max radius as unreachable
		if(distances[p.x][p.y] > max_distance)
		{
			distances[p.x][p.y] = -1;
			continue;
		}

		// Mark all non-empty cells as unreachable (except for cell (from_x; from_y))
		if(field[p.x][p.y].player_num != 0 && distances[p.x][p.y] != 0)
		{
			distances[p.x][p.y] = -1;
			continue;
		}

		// Ignore cells with enemy's units
		if(field[p.x][p.y].player_num == settings.enemy_num)
		{
			distances[p.x][p.y] = -1;
			continue;
		}

		// Push all adjacent cells, which weren't analyzed yet, to the cell queue
		for(int i = 0; i < DN; i++)
		{
			point p2;
			p2.x = p.x + DX[i];
			p2.y = p.y + DY[i];

			if(distances[p.x][p.y] < max_distance)
			{
				if(inside(p2.x, p2.y, settings.field_radius) && distances[p2.x][p2.y] == -1)
				{
					if(field[p2.x][p2.y].player_num == 0)
					{
						distances[p2.x][p2.y] = distances[p.x][p.y] + 1;
						q.push(p2);
					}
				}
			}
		}
	}
}